package main

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"os"
	//"reflect"
	"runtime"
	"sort"
)

type mss []map[string]string
type msf []map[string]float32
type mapsu map[string]uint32
type mapsf map[string]float32
type mssf map[string]map[string]float32
type MapSorter []Item
type Item struct {
	Key string
	Val float32
}

var u_id string
var book_id string

func main() {
	http.HandleFunc("/index", Index)         //设置访问的路由
	err := http.ListenAndServe(":19890", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
func Index(w http.ResponseWriter, r *http.Request) {
	runtime.GOMAXPROCS(runtime.NumCPU())
	custom_item := getJson("/usr/local/bin/recommend/jsonfile/comm_item.json")
	vip_item := getJson("/usr/local/bin/recommend/jsonfile/vip_item.json")
	r.ParseForm()
	u_id = r.FormValue("user_id")
	book_id = r.FormValue("book_id")
	_ = book_id
	_ = u_id
	//求相似度
	target_arr := make(mssf)
	_ = target_arr
	//计算mod
	target_arr[u_id] = custom_item[u_id]
	target_mod := getMod(target_arr[u_id])
	_ = target_mod
	similar_ratio, neiborKey := getsimilarPerson(target_mod, target_arr, vip_item)
	_ = similar_ratio
	//相邻vip顾客的id
	_ = neiborKey
	tarPoint_list := getRecommend(similar_ratio, neiborKey, target_arr, vip_item)
	_ = tarPoint_list
	tar_custom_item, _ := json.Marshal(tarPoint_list)
	fmt.Fprintf(w, string(tar_custom_item))
}
func NewMapSorter(m map[string]float32) MapSorter {
	ms := make(MapSorter, 0, len(m))

	for k, v := range m {
		ms = append(ms, Item{k, v})
	}

	return ms
}

func (ms MapSorter) Len() int {
	return len(ms)
}

func (ms MapSorter) Less(i, j int) bool {
	return ms[i].Val > ms[j].Val // 按值排序
	//return ms[i].Key < ms[j].Key // 按键排序
}

func (ms MapSorter) Swap(i, j int) {
	ms[i], ms[j] = ms[j], ms[i]
}

func getRecommend(similar_ratio mapsf, neiborKey []string, target_arr mssf, vip_item mssf) mapsf {
	var similar_sum float32
	for _, val := range similar_ratio {
		similar_sum += val
	}
	//left 用户平均评分
	var num float32
	var target_point float32 //
	for _, val := range target_arr[u_id] {
		if val != 0 {
			num += 1
			target_point += val
		}
	}
	target_aver := target_point / num //平均1.5
	//up 用户相似度*（该项目相似用户评分-相似用户平均评分）
	neibor_aver := make(map[string]float32)
	for _, val := range neiborKey {
		var neibor_point float32 = 0
		var length float32 = 0
		for _, cval := range vip_item[val] {
			if cval != 0 {
				neibor_point += cval
				length += 1
			}
		}
		neibor_aver[val] = neibor_point / length //相似用户平均评分
	}
	may_point := make(map[string]float32)
	for tkey, tval := range target_arr[u_id] {
		if tval == 0 {
			var upsum float32
			for _, nval := range neiborKey {
				upsum += similar_ratio[nval] * (vip_item[nval][tkey] - neibor_aver[nval])

			}
			may_point[tkey] = target_aver + upsum/similar_sum
		}
	}
	var rec_id []string
	for _, vpoint := range vip_item {
		if vpoint[book_id] > 0 {
			for rid, rpoint := range vpoint {
				if rpoint > 0 && rid != book_id {
					num := 0
					for _, val := range rec_id {
						if val == book_id {
							num += 1
							break
						}
					}
					if num == 0 {
						rec_id = append(rec_id, rid)
					}
				}
			}
		}
	}

	recommend_point := make(map[string]float32)
	if len(rec_id) < 6 {
		m := may_point
		ms := NewMapSorter(m)
		sort.Sort(ms)
		re_recommend := make(map[string]float32)
		for _, id := range rec_id {
			re_recommend[id] = may_point[id]
		}
		mc := re_recommend
		md := NewMapSorter(mc)
		sort.Sort(md)
		for _, item := range md {
			recommend_point[item.Key] = item.Val
		}
		sum := 0
		var filter_id []string
		for _, item := range ms {
			filter_id = append(filter_id, item.Key)
			sum += 1
			if sum >= 6 {
				break
			}
		}
		for _, val := range filter_id {
			sum = 0
			for _, rval := range rec_id {
				if val == rval {
					sum += 1
					break
				}
			}
			if sum == 0 && len(recommend_point) < 6 {
				recommend_point[val] = may_point[val]
			}
		}
	} else {
		for _, val := range rec_id {
			recommend_point[val] = may_point[val]
		}
		m := recommend_point
		ms := NewMapSorter(m)
		sort.Sort(ms)
		re_recommend := make(map[string]float32)
		for _, item := range ms {
			if len(re_recommend) < 6 {
				re_recommend[item.Key] = item.Val
			} else {
				break
			}
		}
		recommend_point = re_recommend
	}
	return recommend_point
}

func getsimilarPerson(targetMod float32, target_arr mssf, vip_item mssf) (mapsf, []string) {
        similar_ratio := make(map[string]float32)
	var neiborKey []string
	for key, val := range vip_item {
		if u_id == key {
			continue
		} else {
			var ride_result float32 = 0
			for ck, cv := range target_arr[u_id] {
				ride_result += cv * val[ck]
			}
			partMod := float32(getMod(val))
			similar := ride_result / (targetMod * partMod)
			if similar > 0 {
				similar_ratio[key] = similar
				neiborKey = append(neiborKey, key)
			}
		}

	}
	//+前10推荐
	return similar_ratio, neiborKey

}
func getMod(target map[string]float32) float32 {
	var mod float64 = 0
	for _, v := range target {
		mod += math.Pow(float64(v), 2)
	}
	return float32(math.Sqrt(mod))
}
func saveJson(json_custom_item []byte, file string) {
	fout, _ := os.Create(file)
	fout.Write(json_custom_item)
	defer fout.Close()

}
func getJson(file_url string) map[string]map[string]float32 {
	fileInfo, _ := os.Stat(file_url)
	fileSize := fileInfo.Size()
	fl, _ := os.Open(file_url)
	defer fl.Close()
	buf := make([]byte, fileSize)
	for {
		n, _ := fl.Read(buf)
		if 0 == n {
			break
		}
	}
	var r interface{}
	json.Unmarshal(buf, &r)
	m := r.(map[string]interface{})
	custom_item := make(map[string]map[string]float32)
	_ = custom_item
	for k, v := range m {
		map_right := make(map[string]float32)
		switch rv := v.(type) {
		case map[string]interface{}:
			for i, u := range rv {
				switch uv := u.(type) {
				case float64:
					map_right[i] = float32(uv)
				}
			}

		}
		custom_item[k] = map_right
	}

	return custom_item

}
